#include "mainwindow.h"
#include "qfilesearchdialog.h"

#include <QActionGroup>
#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QKeyEvent>
#include <QMenuBar>
#include <QMessageBox>
#include <QSet>

const uint32_t maxEmuSpeed = 800; // Maximum speed for the emulator

class MainWindowPrivate
{
public:
    QSet<QString> recentlyOpenedRoms;
    bool showFps = 0;
    QString nesConfigFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings/nes_config.dat";
    NesConfig nesConfig;
    QString emulationConfigFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings/emulation_config.dat";
    EmulationConfig emulationConfig;
    QString gbaConfigFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings/gba_config.dat";
    GbaConfig gbaConfig;
    GameboyConfig gameboyConfig;
    QString gameboyConfigFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings/gameboy_config.dat";
    SnesConfig snesConfig;
    QString snesConfigFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings/snes_config.dat";

    QPictureBox::FilterType filterType = QPictureBox::FilterType::Nearest;
    QPictureBox::ScaleType scaleType = QPictureBox::ScaleType::fitXY;

    MainWindowPrivate(Emulator *emulator)
        : nesConfig(emulator->GetSettings()->GetNesConfig())
        , gbaConfig(emulator->GetSettings()->GetGbaConfig())
        , gameboyConfig(emulator->GetSettings()->GetGameboyConfig())
        , snesConfig(emulator->GetSettings()->GetSnesConfig())
        , emulationConfig(emulator->GetSettings()->GetEmulationConfig())
    {
        // Read form Json file
        QString settingstFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/.settings.json";

        KeyMappingSet keyMappingSet;
        keyMappingSet.Mapping1.A = KeyManager::GetKeyCode("K");
        keyMappingSet.Mapping1.B = KeyManager::GetKeyCode("J");
        keyMappingSet.Mapping1.X = KeyManager::GetKeyCode("I");
        keyMappingSet.Mapping1.Y = KeyManager::GetKeyCode("U");
        keyMappingSet.Mapping1.Up = KeyManager::GetKeyCode("W");
        keyMappingSet.Mapping1.Down = KeyManager::GetKeyCode("S");
        keyMappingSet.Mapping1.Left = KeyManager::GetKeyCode("A");
        keyMappingSet.Mapping1.Right = KeyManager::GetKeyCode("D");
        keyMappingSet.Mapping1.Start = KeyManager::GetKeyCode("Enter");
        keyMappingSet.Mapping1.Select = KeyManager::GetKeyCode("Right Shift");

        keyMappingSet.Mapping2.A = KeyManager::GetKeyCode("Pad1 A");
        keyMappingSet.Mapping2.B = KeyManager::GetKeyCode("Pad1 B");
        keyMappingSet.Mapping2.X = KeyManager::GetKeyCode("Pad1 X");
        keyMappingSet.Mapping2.Y = KeyManager::GetKeyCode("Pad1 Y");
        keyMappingSet.Mapping2.Up = KeyManager::GetKeyCode("Pad1 Up");
        keyMappingSet.Mapping2.Down = KeyManager::GetKeyCode("Pad1 Down");
        keyMappingSet.Mapping2.Left = KeyManager::GetKeyCode("Pad1 Left");
        keyMappingSet.Mapping2.Right = KeyManager::GetKeyCode("Pad1 Right");
        keyMappingSet.Mapping2.Start = KeyManager::GetKeyCode("Pad1 Start");
        keyMappingSet.Mapping2.Select = KeyManager::GetKeyCode("Pad1 Select");

        // NES Default Config
        NesConfig defaultNesConfig;
        uint32_t userPattle[] = {0xFF666666, 0xFF002A88, 0xFF1412A7, 0xFF3B00A4, 0xFF5C007E, 0xFF6E0040, 0xFF6C0600, 0xFF561D00,
                                 0xFF333500, 0xFF0B4800, 0xFF005200, 0xFF004F08, 0xFF00404D, 0xFF000000, 0xFF000000, 0xFF000000,
                                 0xFFADADAD, 0xFF155FD9, 0xFF4240FF, 0xFF7527FE, 0xFFA01ACC, 0xFFB71E7B, 0xFFB53120, 0xFF994E00,
                                 0xFF6B6D00, 0xFF388700, 0xFF0C9300, 0xFF008F32, 0xFF007C8D, 0xFF000000, 0xFF000000, 0xFF000000,
                                 0xFFFFFEFF, 0xFF64B0FF, 0xFF9290FF, 0xFFC676FF, 0xFFF36AFF, 0xFFFE6ECC, 0xFFFE8170, 0xFFEA9E22,
                                 0xFFBCBE00, 0xFF88D800, 0xFF5CE430, 0xFF45E082, 0xFF48CDDE, 0xFF4F4F4F, 0xFF000000, 0xFF000000,
                                 0xFFFFFEFF, 0xFFC0DFFF, 0xFFD3D2FF, 0xFFE8C8FF, 0xFFFBC2FF, 0xFFFEC4EA, 0xFFFECCC5, 0xFFF7D8A5,
                                 0xFFE4E594, 0xFFCFEF96, 0xFFBDF4AB, 0xFFB3F3CC, 0xFFB5EBF2, 0xFFB8B8B8, 0xFF000000, 0xFF000000};
        memcpy(defaultNesConfig.UserPalette, userPattle, sizeof(userPattle));

        defaultNesConfig.Port1.Type = ControllerType::NesController;

        for (int i = 0; i < 11; i++) {
            defaultNesConfig.ChannelVolumes[i] = 100;
        }
        defaultNesConfig.Port1.Keys = keyMappingSet;
        defaultNesConfig.Port1.Keys.Mapping2.X = 0;
        defaultNesConfig.Port1.Keys.Mapping2.Y = 0;
        defaultNesConfig.Port1.Keys.Mapping2.B = KeyManager::GetKeyCode("Pad1 X");
        defaultNesConfig.Port1.Keys.Mapping2.TurboA = KeyManager::GetKeyCode("Pad1 B");
        defaultNesConfig.Port1.Keys.Mapping2.TurboB = KeyManager::GetKeyCode("Pad1 Y");

        // SNES Default Config
        SnesConfig defaultSnesConfig;
        defaultSnesConfig.Port1.Type = ControllerType::SnesController;
        defaultSnesConfig.Port1.Keys = keyMappingSet;

        // GBA Default Config
        GbaConfig defaultGbaConfig;
        defaultGbaConfig.Controller.Type = ControllerType::GbaController;
        defaultGbaConfig.Controller.Keys = keyMappingSet;
        defaultGbaConfig.BlendFrames = true;
        defaultGbaConfig.GbaAdjustColors = true;
        defaultGbaConfig.RamPowerOnState = RamState::AllZeros;

        defaultGbaConfig.ChannelAVol = 100;
        defaultGbaConfig.ChannelBVol = 100;
        defaultGbaConfig.Square1Vol = 100;
        defaultGbaConfig.Square2Vol = 100;
        defaultGbaConfig.NoiseVol = 100;
        defaultGbaConfig.WaveVol = 100;

        GameboyConfig defaultGameboyConfig;
        defaultGameboyConfig.Controller.Type = ControllerType::GameboyController;
        defaultGameboyConfig.Controller.Keys = keyMappingSet;

        QFile settingsFile(settingstFilePath);
        if (settingsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QByteArray data = settingsFile.readAll();
            QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
            if (jsonDoc.isObject()) {
                QJsonObject jsonObj = jsonDoc.object();
                if (jsonObj.contains("recentlyOpenedRoms")) {
                    QJsonArray romsArray = jsonObj["recentlyOpenedRoms"].toArray();
                    for (const QJsonValue &value : romsArray) {
                        QString romPath = value.toString();
                        if (!romPath.isEmpty() && !recentlyOpenedRoms.contains(romPath)) {
                            recentlyOpenedRoms.insert(romPath);
                        }
                    }
                }
                showFps = jsonObj["showFps"].toBool(false);
                filterType = QPictureBox::FilterType(jsonObj["fileterType"].toInt(QPictureBox::FilterType::Linear));
                scaleType = QPictureBox::ScaleType(jsonObj["scaleType"].toInt(QPictureBox::ScaleType::fitCenter));

                QString nesConfigFile = jsonObj["nesConfig"].toString(nesConfigFilePath);
                QString gbaConfigFile = jsonObj["gbaConfig"].toString(gbaConfigFilePath);
                QString emulationConfigFile = jsonObj["emulationConfig"].toString(emulationConfigFilePath);

                QFile nesConfigFileHandle(nesConfigFile);
                if (QFile::exists(nesConfigFile) && nesConfigFileHandle.open(QIODevice::ReadOnly)) {
                    nesConfigFileHandle.read(reinterpret_cast<char *>(&nesConfig), sizeof(nesConfig));
                    nesConfigFileHandle.close();
                } else {
                    memcpy(&nesConfig, &defaultNesConfig, sizeof(NesConfig));
                }

                QFile snesConfigFileHandle(snesConfigFilePath);
                if (QFile::exists(snesConfigFilePath) && snesConfigFileHandle.open(QIODevice::ReadOnly)) {
                    snesConfigFileHandle.read(reinterpret_cast<char *>(&snesConfig), sizeof(snesConfig));
                    snesConfigFileHandle.close();
                } else {
                    memcpy(&snesConfig, &defaultSnesConfig, sizeof(SnesConfig));
                }

                QFile gbaConfigFileHandle(gbaConfigFile);
                if (QFile::exists(gbaConfigFile) && gbaConfigFileHandle.open(QIODevice::ReadOnly)) {
                    gbaConfigFileHandle.read(reinterpret_cast<char *>(&gbaConfig), sizeof(gbaConfig));
                    gbaConfigFileHandle.close();
                } else {
                    memcpy(&gbaConfig, &defaultGbaConfig, sizeof(GbaConfig));
                }

                QFile gameboyConfigFileHandle(gameboyConfigFilePath);
                if (QFile::exists(gameboyConfigFilePath) && gameboyConfigFileHandle.open(QIODevice::ReadOnly)) {
                    gameboyConfigFileHandle.read(reinterpret_cast<char *>(&gameboyConfig), sizeof(gameboyConfig));
                    gameboyConfigFileHandle.close();
                } else {
                    memcpy(&gameboyConfig, &defaultGameboyConfig, sizeof(GameboyConfig));
                }

                QFile emulationConfigFileHandle(emulationConfigFile);
                if (QFile::exists(emulationConfigFile) && emulationConfigFileHandle.open(QIODevice::ReadOnly)) {
                    emulationConfigFileHandle.read(reinterpret_cast<char *>(&emulationConfig), sizeof(emulationConfig));
                    emulationConfigFileHandle.close();
                } else {
                    emulationConfig.EmulationSpeed = 100;
                }
            }
            settingsFile.close();
        } else {
            // If settings file does not exist, use default configurations
            memcpy(&nesConfig, &defaultNesConfig, sizeof(NesConfig));
            memcpy(&gbaConfig, &defaultGbaConfig, sizeof(GbaConfig));
        }

        emulator->GetSettings()->SetNesConfig(nesConfig);
        emulator->GetSettings()->SetSnesConfig(snesConfig);
        emulator->GetSettings()->SetGameboyConfig(gameboyConfig);
        emulator->GetSettings()->SetGbaConfig(gbaConfig);
        emulator->GetSettings()->SetEmulationConfig(emulationConfig);
    }

    ~MainWindowPrivate()
    {
        // Save to Json file
        QString recentFilePath = QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/.settings.json";
        QFile settingsFile(recentFilePath);
        if (settingsFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            QJsonObject jsonObj;
            QJsonArray romsArray;
            for (const QString &rom : recentlyOpenedRoms) {
                romsArray.append(rom);
            }
            jsonObj["showFps"] = showFps;
            jsonObj["fileterType"] = (int)filterType;
            jsonObj["scaleType"] = (int)scaleType;
            jsonObj["recentlyOpenedRoms"] = romsArray;

            jsonObj["nesConfig"] = nesConfigFilePath;
            jsonObj["snesConfig"] = snesConfigFilePath;
            jsonObj["gameboyConfig"] = gameboyConfigFilePath;
            jsonObj["gbaConfig"] = gbaConfigFilePath;
            jsonObj["emulationConfig"] = emulationConfigFilePath;

            if (!QDir(QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings").exists()) {
                QDir().mkpath(QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/Settings");
            }

            // Save nesConfig struct to binary file
            QFile nesConfigFile(nesConfigFilePath);
            if (nesConfigFile.open(QIODevice::WriteOnly)) {
                nesConfigFile.write(reinterpret_cast<const char *>(&nesConfig), sizeof(nesConfig));
                nesConfigFile.close();
            }

            // Save gameboyConfig struct to binary file
            QFile gameboyConfigFile(gameboyConfigFilePath);
            if (gameboyConfigFile.open(QIODevice::WriteOnly)) {
                gameboyConfigFile.write(reinterpret_cast<const char *>(&gameboyConfig), sizeof(gameboyConfig));
                gameboyConfigFile.close();
            }

            // Save snesConfig struct to binary file
            QFile snesConfigFile(snesConfigFilePath);
            if (snesConfigFile.open(QIODevice::WriteOnly)) {
                snesConfigFile.write(reinterpret_cast<const char *>(&snesConfig), sizeof(snesConfig));
                snesConfigFile.close();
            }

            // Save emulationConfig struct to binary file
            QFile emulationConfigFile(emulationConfigFilePath);
            if (emulationConfigFile.open(QIODevice::WriteOnly)) {
                emulationConfigFile.write(reinterpret_cast<const char *>(&emulationConfig), sizeof(emulationConfig));
                emulationConfigFile.close();
            }

            // Save gbaConfig struct to binary file
            QFile gbaConfigFile(gbaConfigFilePath);
            if (gbaConfigFile.open(QIODevice::WriteOnly)) {
                gbaConfigFile.write(reinterpret_cast<const char *>(&gbaConfig), sizeof(gbaConfig));
                gbaConfigFile.close();
            }

            QJsonDocument jsonDoc(jsonObj);
            settingsFile.write(jsonDoc.toJson());
            settingsFile.close();
        }
    }

    friend class MainWindow;
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , m_emulator(new Emulator())
    , m_pictureBox(new QPictureBox(this))
    , m_qRender(new QRender(m_emulator))
    , m_qMouseManager(new QMouseManager(this))
    , m_qKeyManager(new QKeyManager(m_emulator, this))
    , m_miniSoundManager(new MiniSoundManager(m_emulator))
{
    initEmulator();
    p = new MainWindowPrivate(m_emulator);
    m_pictureBox->setScaleType(p->scaleType);
    m_pictureBox->setFilterType(p->filterType);
    initUI();

    connect(m_qRender, &QRender::frameUpdated, m_pictureBox, &QPictureBox::setImage);
}

MainWindow::~MainWindow()
{
    if (m_emulator) {
        if (m_emulator->IsRunning()) {
            m_emulator->GetSaveStateManager()->SaveState();
        }
        m_emulator->Release();
        delete m_emulator;
    }
    if (p) {
        delete p;
    }
}

void MainWindow::initEmulator()
{
    m_emulator->Initialize();
}

void MainWindow::initUI()
{
    QMenuBar *menuBar = new QMenuBar(this);

    // 文件菜单
    QMenu *fileMenu = new QMenu(tr("文件"), menuBar);
    QAction *openAction = new QAction(tr("打开"), fileMenu);
    connect(openAction, &QAction::triggered, this, &MainWindow::openRomFile);
    openAction->setShortcut(QKeySequence::Open);
    fileMenu->addAction(openAction);
    addAction(openAction);

    fileMenu->addSeparator();

    QMenu *saveStateMenu = new QMenu(tr("保存进度"), fileMenu);
    for (int i = 0; i < 10; ++i) {
        QAction *saveAction = new QAction(tr("进度 %1").arg(i + 1), saveStateMenu);
        connect(saveAction, &QAction::triggered, [this, i]() {
            m_emulator->GetSaveStateManager()->SaveState(i);
        });
        saveStateMenu->addAction(saveAction);
        if (i < 6) {
            saveAction->setShortcut(QKeySequence(Qt::SHIFT | (Qt::Key_F1 + i)));
        }
    }
    QAction *saveToFileAction = new QAction(tr("保存到文件"), saveStateMenu);
    connect(saveToFileAction, &QAction::triggered, [this]() {
        QString filePath = QFileDialog::getSaveFileName(this, tr("保存进度"), QString(), tr("Save State Files (*.mss)"));
        if (!filePath.isEmpty()) {
            m_emulator->GetSaveStateManager()->SaveState(filePath.toStdString(), true);
        }
    });
    saveStateMenu->addSeparator();
    saveStateMenu->addAction(saveToFileAction);
    saveToFileAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
    addAction(saveToFileAction);
    fileMenu->addMenu(saveStateMenu);

    QMenu *loadStateMenu = new QMenu(tr("加载进度"), fileMenu);
    for (int i = 0; i < 10; ++i) {
        QAction *loadAction = new QAction(tr("进度 %1").arg(i + 1), loadStateMenu);
        connect(loadAction, &QAction::triggered, [this, i]() {
            m_emulator->GetSaveStateManager()->LoadState(i);
        });
        loadStateMenu->addAction(loadAction);
        if (i < 6) {
            loadAction->setShortcut(QKeySequence(Qt::Key_F1 + i));
        }
        addAction(loadAction);
    }
    QAction *loadFromFileAction = new QAction(tr("从文件加载"), loadStateMenu);
    connect(loadFromFileAction, &QAction::triggered, [this]() {
        QString filePath = QFileDialog::getOpenFileName(this, tr("加载进度"), QString(), tr("Save State Files (*.mss)"));
        if (!filePath.isEmpty()) {
            m_emulator->GetSaveStateManager()->LoadState(filePath.toStdString(), true);
        }
    });
    loadStateMenu->addSeparator();
    loadStateMenu->addAction(loadFromFileAction);
    loadFromFileAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_L));
    addAction(loadFromFileAction);
    fileMenu->addMenu(loadStateMenu);
    fileMenu->addSeparator();

    QMenu *recentGamesMenu = new QMenu(tr("最近游戏"), fileMenu);
    auto addRecentGame = [this, recentGamesMenu](const QString &romPath) {
        QAction *recentAction = new QAction(romPath, recentGamesMenu);
        connect(recentAction, &QAction::triggered, [this, romPath]() {
            if (m_emuThread && m_emuThread->isRunning()) {
                m_emulator->Stop(false, false, true);
                m_emuThread->wait();
                delete m_emuThread;
                m_emuThread = nullptr;
            }

            m_emuThread = QThread::create([this, romPath]() {
                m_emulator->GetGameClient()->Disconnect();
                VirtualFile romFile(romPath.toStdString());
                if (m_emulator->LoadRom(romFile, VirtualFile())) {
                    m_emulator->GetSaveStateManager()->LoadState();
                }
            });

            m_emuThread->start();

            Q_EMIT emulatorStarted();
        });
        recentGamesMenu->addAction(recentAction);
    };

    for (const QString &rom : p->recentlyOpenedRoms) {
        addRecentGame(rom);
    }
    connect(this, &MainWindow::recentGameAdded, this, [addRecentGame](const QString &romPath) {
        addRecentGame(romPath);
    });

    fileMenu->addMenu(recentGamesMenu);
    fileMenu->addSeparator();

    QAction *exitAction = new QAction(tr("退出"), fileMenu);
    connect(exitAction, &QAction::triggered, this, &MainWindow::close);
    exitAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
    fileMenu->addAction(exitAction);
    addAction(exitAction);

    // 游戏菜单
    QMenu *gameMenu = new QMenu(tr("游戏"), this);
    QAction *pauseAction = new QAction(tr("暂停/继续"), gameMenu);
    connect(pauseAction, &QAction::triggered, this, [this]() {
        if (m_emulator->IsPaused()) {
            m_emulator->Resume();
        } else {
            m_emulator->Pause();
        }
    });
    pauseAction->setShortcut(QKeySequence(Qt::Key_Escape));
    gameMenu->addAction(pauseAction);
    addAction(pauseAction);

    gameMenu->addSeparator();

    QAction *resetAction = new QAction(tr("重置"), gameMenu);
    connect(resetAction, &QAction::triggered, this, [this]() {
        if (m_emulator->IsRunning()) {
            m_emulator->GetSaveStateManager()->SaveState();
            m_emulator->Reset();
        }
    });
    resetAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_R));
    gameMenu->addAction(resetAction);
    addAction(resetAction);

    QAction *powerCycleAction = new QAction(tr("电源循环"), gameMenu);
    connect(powerCycleAction, &QAction::triggered, this, [this]() {
        if (m_emulator->IsRunning())
            m_emulator->GetSaveStateManager()->SaveState();

        m_emulator->PowerCycle();
    });
    powerCycleAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_T));
    gameMenu->addAction(powerCycleAction);
    addAction(powerCycleAction);

    QAction *reloadRomAction = new QAction(tr("重新加载ROM"), gameMenu);
    connect(reloadRomAction, &QAction::triggered, [this]() {
        if (m_emuThread && m_emuThread->isRunning()) {
            m_emulator->GetSaveStateManager()->SaveState();
            m_emulator->Stop(false, false, true);
            m_emuThread->wait();
            Q_EMIT emulatorStopped();
            delete m_emuThread;
            m_emuThread = nullptr;
        }
        m_emuThread = QThread::create([this]() {
            m_emulator->ReloadRom(false);
        });
        m_emuThread->start();
        Q_EMIT emulatorStarted();
    });
    reloadRomAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_R));
    gameMenu->addAction(reloadRomAction);
    addAction(reloadRomAction);

    gameMenu->addSeparator();

    QAction *powerOffAction = new QAction(tr("关闭电源"), gameMenu);
    connect(powerOffAction, &QAction::triggered, this, [this]() {
        if (!m_emuThread)
            return;

        m_emulator->GetSaveStateManager()->SaveState();
        m_emulator->GetGameClient()->Disconnect();
        m_emulator->Stop(false, false, true);
        m_emuThread->wait();
        Q_EMIT emulatorStopped();
        delete m_emuThread;
        m_emuThread = nullptr;
        QImage emptyImage(100, 100, QImage::Format_ARGB32);
        emptyImage.fill(Qt::black);
        m_pictureBox->setImage(emptyImage);
    });
    gameMenu->addAction(powerOffAction);
    addAction(powerOffAction);

    // 设置菜单
    QMenu *settingsMenu = new QMenu(tr("设置"), menuBar);
    QMenu *speedMenu = new QMenu(tr("速度"), settingsMenu);
    QAction *normalSpeedAction = new QAction(tr("正常"), speedMenu);
    QAction *maxSpeedAction = new QAction(tr("最大速度"), speedMenu);
    QAction *tripleSpeedAction = new QAction(tr("300%"), speedMenu);
    QAction *doubleSpeedAction = new QAction(tr("200%"), speedMenu);
    QAction *halfSpeedAction = new QAction(tr("50%"), speedMenu);
    QAction *quarterSpeedAction = new QAction(tr("25%"), speedMenu);

    QActionGroup *speedActionGroup = new QActionGroup(speedMenu);
    speedActionGroup->addAction(normalSpeedAction);
    speedActionGroup->addAction(maxSpeedAction);
    speedActionGroup->addAction(tripleSpeedAction);
    speedActionGroup->addAction(doubleSpeedAction);
    speedActionGroup->addAction(halfSpeedAction);
    speedActionGroup->addAction(quarterSpeedAction);

    normalSpeedAction->setCheckable(true);
    maxSpeedAction->setCheckable(true);
    tripleSpeedAction->setCheckable(true);
    doubleSpeedAction->setCheckable(true);
    halfSpeedAction->setCheckable(true);
    quarterSpeedAction->setCheckable(true);

    normalSpeedAction->setChecked(p->emulationConfig.EmulationSpeed == 100);
    maxSpeedAction->setChecked(p->emulationConfig.EmulationSpeed == maxEmuSpeed);
    tripleSpeedAction->setChecked(p->emulationConfig.EmulationSpeed == 300);
    doubleSpeedAction->setChecked(p->emulationConfig.EmulationSpeed == 200);
    halfSpeedAction->setChecked(p->emulationConfig.EmulationSpeed == 50);
    quarterSpeedAction->setChecked(p->emulationConfig.EmulationSpeed == 25);

    connect(normalSpeedAction, &QAction::triggered, this, [=](bool checked) {
        if (!checked)
            return;

        p->emulationConfig.EmulationSpeed = 100;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    speedMenu->addAction(normalSpeedAction);
    speedMenu->addSeparator();

    QAction *increaseSpeedAction = new QAction(tr("加速"), speedMenu);
    connect(increaseSpeedAction, &QAction::triggered, this, [this]() {
        p->emulationConfig.EmulationSpeed += 25;
        if (p->emulationConfig.EmulationSpeed > maxEmuSpeed)
            p->emulationConfig.EmulationSpeed = maxEmuSpeed;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    increaseSpeedAction->setShortcut(QKeySequence(Qt::Key_Equal));
    speedMenu->addAction(increaseSpeedAction);
    addAction(increaseSpeedAction);

    QAction *decreaseSpeedAction = new QAction(tr("减速"), speedMenu);
    connect(decreaseSpeedAction, &QAction::triggered, this, [this]() {
        p->emulationConfig.EmulationSpeed -= 25;
        if (p->emulationConfig.EmulationSpeed < 25)
            p->emulationConfig.EmulationSpeed = 25;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    decreaseSpeedAction->setShortcut(QKeySequence(Qt::Key_Minus));
    speedMenu->addAction(decreaseSpeedAction);
    addAction(decreaseSpeedAction);

    connect(maxSpeedAction, &QAction::triggered, this, [=](bool checked) {
        if (!checked)
            return;

        p->emulationConfig.EmulationSpeed = maxEmuSpeed;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    maxSpeedAction->setShortcut(QKeySequence(Qt::Key_F9));
    speedMenu->addAction(maxSpeedAction);
    addAction(maxSpeedAction);

    speedMenu->addSeparator();

    connect(tripleSpeedAction, &QAction::triggered, this, [=](bool checked) {
        if (!checked)
            return;

        p->emulationConfig.EmulationSpeed = 300;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    speedMenu->addAction(tripleSpeedAction);
    addAction(tripleSpeedAction);

    connect(doubleSpeedAction, &QAction::triggered, this, [=](bool checked) {
        if (!checked)
            return;
        p->emulationConfig.EmulationSpeed = 200;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    speedMenu->addAction(doubleSpeedAction);
    addAction(doubleSpeedAction);

    connect(halfSpeedAction, &QAction::triggered, this, [=](bool checked) {
        if (!checked)
            return;
        p->emulationConfig.EmulationSpeed = 50;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    speedMenu->addAction(halfSpeedAction);
    addAction(halfSpeedAction);

    connect(quarterSpeedAction, &QAction::triggered, this, [=](bool checked) {
        if (!checked)
            return;
        p->emulationConfig.EmulationSpeed = 25;
        m_emulator->GetSettings()->SetEmulationConfig(p->emulationConfig);
    });
    speedMenu->addAction(quarterSpeedAction);
    addAction(quarterSpeedAction);

    speedMenu->addSeparator();
    QAction *showFpsAction = new QAction(tr("显示帧率"), speedMenu);
    showFpsAction->setCheckable(true);
    showFpsAction->setChecked(p->showFps);
    m_fpsLabel = new QLabel(this);
    m_fpsLabel->setStyleSheet("color: white; padding: 5px;");
    m_fpsLabel->setFont(QFont("Arial", 10));
    m_fpsLabel->move(width() - 100, menuBar->height() + 5);
    m_fpsLabel->setVisible(false);
    m_fpsLabel->setAlignment(Qt::AlignRight | Qt::AlignTop);
    connect(showFpsAction, &QAction::triggered, this, [this](bool checked) {
        p->showFps = checked;
        m_fpsLabel->setVisible(checked);
    });
    showFpsAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_F));
    speedMenu->addAction(showFpsAction);
    addAction(showFpsAction);

    connect(m_pictureBox, &QPictureBox::fpsChanged, this, [this](int fps) {
        if (p->showFps)
            m_fpsLabel->setText(QString("FPS: %1").arg(fps));
    });
    settingsMenu->addMenu(speedMenu);

    QMenu *videoFilterMenu = new QMenu(tr("视频滤镜"), settingsMenu);
    QAction *linearFilterAction = new QAction(tr("线性滤镜"), videoFilterMenu);
    QAction *nearestFilterAction = new QAction(tr("最近临滤镜"), videoFilterMenu);
    QActionGroup *fileterActionGroup = new QActionGroup(videoFilterMenu);
    fileterActionGroup->addAction(linearFilterAction);
    fileterActionGroup->addAction(nearestFilterAction);

    linearFilterAction->setCheckable(true);
    nearestFilterAction->setCheckable(true);
    linearFilterAction->setChecked(p->filterType == QPictureBox::FilterType::Linear);
    nearestFilterAction->setChecked(p->filterType == QPictureBox::FilterType::Nearest);
    connect(linearFilterAction, &QAction::triggered, this, [this](bool checked) {
        p->filterType = QPictureBox::FilterType::Linear;
        m_pictureBox->setFilterType(p->filterType);
    });
    connect(nearestFilterAction, &QAction::triggered, this, [this](bool checked) {
        p->filterType = QPictureBox::FilterType::Nearest;
        m_pictureBox->setFilterType(p->filterType);
    });
    videoFilterMenu->addAction(linearFilterAction);
    videoFilterMenu->addAction(nearestFilterAction);
    settingsMenu->addMenu(videoFilterMenu);

    QMenu *videoScaleMenu = new QMenu(tr("视频缩放"), settingsMenu);
    QAction *fitCenterAction = new QAction(tr("原始比例"), videoScaleMenu);
    QAction *fitXYAction = new QAction(tr("全部填充"), videoScaleMenu);
    QActionGroup *videoScaleActionGroup = new QActionGroup(videoScaleMenu);
    videoScaleActionGroup->addAction(fitXYAction);
    videoScaleActionGroup->addAction(fitCenterAction);
    fitCenterAction->setCheckable(true);
    fitXYAction->setCheckable(true);
    fitCenterAction->setChecked(p->scaleType == QPictureBox::ScaleType::fitCenter);
    fitXYAction->setChecked(p->scaleType == QPictureBox::ScaleType::fitXY);
    connect(fitCenterAction, &QAction::triggered, this, [this](bool checked) {
        if (!checked)
            return;

        p->scaleType = QPictureBox::ScaleType::fitCenter;
        m_pictureBox->setScaleType(p->scaleType);
    });
    connect(fitXYAction, &QAction::triggered, this, [this](bool checked) {
        if (!checked)
            return;

        p->scaleType = QPictureBox::ScaleType::fitXY;
        m_pictureBox->setScaleType(p->scaleType);
    });
    videoScaleMenu->addAction(fitCenterAction);
    videoScaleMenu->addAction(fitXYAction);

    settingsMenu->addMenu(videoScaleMenu);

    QAction *preferencesAction = new QAction(tr("首选项"), settingsMenu);
    connect(preferencesAction, &QAction::triggered, this, [this]() {
        if (!m_settingsDialog)
            m_settingsDialog = new QSettingsDialog(m_emulator, this);

        if (m_settingsDialog->exec() == QDialog::Accepted) {
            p->nesConfig = m_emulator->GetSettings()->GetNesConfig();
            p->emulationConfig = m_emulator->GetSettings()->GetEmulationConfig();
        };
    });
    settingsMenu->addAction(preferencesAction);
    addAction(preferencesAction);

    QAction *fullScrenToggleAction = new QAction(tr("全屏/还原"), this);
    connect(fullScrenToggleAction, &QAction::triggered, this, [this, menuBar]() {
        if (isFullScreen()) {
            showNormal();
            menuBar->show();
        } else {
            showFullScreen();
            menuBar->hide();
        }
    });
    fullScrenToggleAction->setShortcut(QKeySequence(Qt::Key_F11));
    addAction(fullScrenToggleAction);

    menuBar->addMenu(fileMenu);
    menuBar->addMenu(gameMenu);
    menuBar->addMenu(settingsMenu);
    setMenuBar(menuBar);

    // 设置菜单按钮初始状态
    saveStateMenu->setEnabled(m_emulator->IsRunning());
    loadStateMenu->setEnabled(m_emulator->IsRunning());
    recentGamesMenu->setEnabled(!p->recentlyOpenedRoms.isEmpty());
    pauseAction->setEnabled(m_emulator->IsRunning());
    resetAction->setEnabled(m_emulator->IsRunning());
    powerCycleAction->setEnabled(m_emulator->IsRunning());
    powerOffAction->setEnabled(m_emulator->IsRunning());
    reloadRomAction->setEnabled(m_emulator->IsRunning());
    connect(this, &MainWindow::emulatorStarted, this, [=]() {
        saveStateMenu->setEnabled(true);
        loadStateMenu->setEnabled(true);

        pauseAction->setEnabled(true);
        resetAction->setEnabled(true);
        powerCycleAction->setEnabled(true);
        powerOffAction->setEnabled(true);
        reloadRomAction->setEnabled(true);
    });

    connect(this, &MainWindow::emulatorStopped, this, [=]() {
        saveStateMenu->setEnabled(false);
        loadStateMenu->setEnabled(false);
        recentGamesMenu->setEnabled(!p->recentlyOpenedRoms.isEmpty());

        pauseAction->setEnabled(false);
        resetAction->setEnabled(false);
        powerCycleAction->setEnabled(false);
        powerOffAction->setEnabled(false);
        reloadRomAction->setEnabled(false);
    });

    setCentralWidget(m_pictureBox);

    resize(maxEmuSpeed, 600);
    setWindowTitle(tr("Emulator"));
}

void MainWindow::openRomFile()
{
    QString filter = "All supported files (*.sfc *.fig *.smc *.bs *.st *.spc *.nes *.fds *.qd "
                     "*.unif *.unf *.studybox *.nsf *.nsfe *.gb *.gbc *.gbx *.gbs *.pce *.sgx "
                     "*.cue *.hes *.sms *.gg *.sg *.col *.gba *.ws *.wsc *.zip *.7z *.ips *.bps);;"
                     "SNES ROM files (*.sfc *.fig *.smc *.bs *.st *.spc);;"
                     "NES ROM files (*.nes *.fds *.qd *.unif *.unf *.studybox *.nsf *.nsfe);;"
                     "GB ROM files (*.gb *.gbc *.gbx *.gbs);;"
                     "GBA ROM files (*.gba);;"
                     "PC Engine ROM files (*.pce *.sgx *.cue *.hes);;"
                     "SMS / GG ROM files (*.sms *.gg);;"
                     "SG-1000 ROM files (*.sg);;"
                     "ColecoVision ROM files (*.col);;"
                     "WonderSwan ROM files (*.ws *.wsc);;"
                     "Patch files (IPS/BPS) (*.ips *.bps);;"
                     "All files (*)";

    QString selectedFile;
    QString databasePath = m_dataBasePath.isEmpty() ? QString::fromStdString(FolderUtilities::GetHomeFolder()) + "/file_index.db" : m_dataBasePath;
    if (QFile::exists(databasePath)) {
        QFileSearchDialog searchDialog(this, databasePath);
        searchDialog.exec();
        if (searchDialog.result() == QDialog::Accepted) {
            selectedFile = searchDialog.selectedFile();
        }
    } else {
        selectedFile = QFileDialog::getOpenFileName(this, tr("打开ROM文件"), QString(), filter);
    }

    if (selectedFile.isEmpty())
        return;

    std::string filePath = selectedFile.toStdString();

    if (m_emuThread && m_emuThread->isRunning()) {
        m_emulator->Stop(false, false, true);
        m_emuThread->wait();
        Q_EMIT emulatorStopped();
        delete m_emuThread;
        m_emuThread = nullptr;
    }

    m_emuThread = QThread::create([this, filePath]() {
        m_emulator->GetGameClient()->Disconnect();
        VirtualFile romFile(filePath);
        if (m_emulator->LoadRom(romFile, VirtualFile())) {
            m_emulator->GetSaveStateManager()->LoadState();
        }
    });

    m_emuThread->start();

    p->recentlyOpenedRoms.insert(selectedFile);

    Q_EMIT recentGameAdded(selectedFile);
    Q_EMIT emulatorStarted();
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    if (m_fpsLabel) {
        m_fpsLabel->move(width() - 100, menuBar()->height() + 5);
    }
}
